package com.piece.core.web.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@Slf4j
public class InterceptorHookManager {

    private Map<String, Set<InterceptorHook>> interceptorHookSetMap = new HashMap<>();
    private Map<String, InterceptorHook> interceptorHookMap;

    public InterceptorHookManager(Map<String, InterceptorHook> interceptorHookMap) {
        log.info("加载 InterceptorHookManager ...");
        this.interceptorHookMap = interceptorHookMap;
        this.init();
    }

    /**
     * 获取拦截类的所有钩子
     */
    private void init() {
        if (null != this.interceptorHookMap) {
            Iterator<Map.Entry<String, InterceptorHook>> it = this.interceptorHookMap.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, InterceptorHook> entry = it.next();
                log.info("加载 InterceptorHookManager --> {}", entry.getKey());

                InterceptorHook interceptorHook = entry.getValue();
                String[] names = interceptorHook.getInterceptor();
                addInterceptorHook(names, interceptorHook);
            }
        }
    }

    /**
     * 添加钩子
     */
    private void addInterceptorHook(String[] names, InterceptorHook interceptorHook) {
        if (null == names) {
            names = new String[]{"ALL"};
        }

        for (String name : names) {
            if (!this.interceptorHookSetMap.containsKey(name)) {
                Set<InterceptorHook> list = new HashSet<>();
                list.add(interceptorHook);
                this.interceptorHookSetMap.put(name, list);
            } else {
                this.interceptorHookSetMap.get(name).add(interceptorHook);
            }
        }
    }

    /**
     * 删除钩子
     */
    public void removeInterceptorHook(InterceptorHook hook) {
        Iterator<Map.Entry<String, Set<InterceptorHook>>> it = this.interceptorHookSetMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Set<InterceptorHook>> entry = it.next();
            entry.getValue().remove(hook);
        }
    }

    public Set<InterceptorHook> getInterceptorHook(HandlerMethod handlerMethod) {
        Set<InterceptorHook> interceptorHooks = new HashSet<>();
        String clazz = handlerMethod.getBean().getClass().getName();
        String method = handlerMethod.getMethod().getName();
        if (clazz.indexOf("$$") != -1) {
            clazz = clazz.substring(0, clazz.indexOf("$$"));
        }
        Set<InterceptorHook> c = this.interceptorHookSetMap.get(clazz);
        Set<InterceptorHook> m = this.interceptorHookSetMap.get(clazz + "#" + method);
        Set<InterceptorHook> a = this.interceptorHookSetMap.get("ALL");
        if (null != m) {
            interceptorHooks.addAll(m);
        }
        if (null != c) {
            interceptorHooks.addAll(c);
        }
        if (null != a) {
            interceptorHooks.addAll(a);
        }
        return interceptorHooks;
    }

    public void preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Set<InterceptorHook> interceptorHookSet = getInterceptorHook(handlerMethod);
            for (InterceptorHook interceptorHook : interceptorHookSet) {
                interceptorHook.preHandle(request, response, handlerMethod);
            }
        }
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Set<InterceptorHook> interceptorHookSet = getInterceptorHook(handlerMethod);
            for (InterceptorHook interceptorHook : interceptorHookSet) {
                interceptorHook.postHandle(request, response, handlerMethod);
            }
        }
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Set<InterceptorHook> interceptorHookSet = getInterceptorHook(handlerMethod);
            for (InterceptorHook interceptorHook : interceptorHookSet) {
                interceptorHook.afterCompletion(request, response, handlerMethod, ex);
            }
        }
    }

    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Set<InterceptorHook> interceptorHookSet = getInterceptorHook(handlerMethod);
            for (InterceptorHook interceptorHook : interceptorHookSet) {
                interceptorHook.afterConcurrentHandlingStarted(request, response, handlerMethod);
            }
        }
    }
}
